#include <iostream>
#include <memory>

using namespace std;

typedef struct student_t
{
    int value;
    string name;
}stu;

/* c++ 版本: c++98 c++03 c++11 c++14 c++17 c++20
 * c   版本: c89 c90 c95 c99 c11 c17
 *
 * 
 */


/*
 * std::auto_ptr 在c++11 以及以上版本被弃用,只能在c++11以下，包括c++03 c++98 等可以使用
 *
 * 
*/
int main(int argc,char * argv[])
{

#if 1
    // smart_ptr<type> pobj(new type(value)); 只能去这样定义，因为其构造函数阻止了其隐式转换
    // 智能指针本质上是一个对象，用来托管对象的地址，可以通过pobj.get()来获取其托管对象的地址
    // ptr.get() 与*ptr 都是取其对象的值
    // auto_ptr 在所有权被转移后，如果访问原来的智能指针，造成程序的错误，因此逐渐被弃用
    // 此外auto_ptr对象并不能作为STL容器的元素，因为C++的STL容器对于容器元素类型的要求是有值语义，即可以赋值和复制，
    // auto_ptr在赋值和复制时都进行了特殊操作；也不能声明为数组，因为auto_ptr无法识别数组，其内部析构时是用的delete而非delete []，它只会析构一次，导致内存泄漏：
    // auto_ptr意义不明确，使用浅拷贝方式时，两个对象拥有同一块资源，这样就会调用两次析构函数，有可能导致程序崩溃


    // 不适应auto_ptr的指针
    /*
     *  ①auto_ptr之间不能共享拥有权

            一个auto_ptr不能指向另一个auto_ptr所拥有的对象，否则，当第一个指针删除该对象后，另一个指针就会指向一个已经被销毁的对象，此时如果再使用那个指针进行读写操作，就会引发错误。

        ②不存在针对array而设计的auto_ptr

            auto_ptr不可以指向array，因为auto_ptr是通过delete而不是delete[ ]来释放其所拥有的对象。

        ③auto_ptr并不是一个全能的、“四海通用”型的指针

            并非任何适用智能型指针的地方，都适用auto_ptr。

        ④auto_ptr不满足STL容器对其元素的要求

            由于在拷贝和赋值动作之后，原本的auto_ptr和新产生的auto_ptr并不相等。原本的auto_ptr会交出拥有权，而不是拷贝给新的auto_ptr。
     *
     * 
    */
    auto_ptr<int> ptr(new int(100));
    
    // ptr.release(); // 取消对对象的托管
    
    int *ptr1 = ptr.get();
    
    cout << "ptr1: " << ptr1 << " " << *ptr1 << endl;

    cout << "ptr: " << ptr.get() << " " << *ptr << endl;
    *ptr = 20;
    cout << *ptr << endl;
    
    cout << "**********" << endl;
    auto_ptr<int> ptr3(ptr); //转移对象的所有权

    cout << "ptr3: " << ptr3.get() << " " << *ptr3 << endl;   
    // cout << *ptr << endl;  // 此时ptr已经被清空
    auto_ptr<int> ptr4 = ptr3; //转移对象的所有权 ，这里是重载赋值
    cout << "ptr4: " << ptr4.get() << " " << *ptr4 << endl;   
    // cout << *ptr3 << endl;   // 此时ptr3已经被清空

    // ptr4.reset(obj) 用来替换智能指针管理的对象，如果传入的为空，则释放托管对象资源并置空，如果传入另一指针，先释放前一指针，再托管后面的。
    ptr4.reset(new int(67));
    cout << "After ptr4: " << ptr4.get() << " " << *ptr4 << endl; 
    
    stu *stu1 = new stu();

    stu1->name = "Tom";
    stu1->value = 19;

    auto_ptr<stu> stu_ptr1(stu1); //用stu_ptr1来管理所托管的对象
    // auto_ptr<stu> stu_ptr2(stu1);
    
    cout << "name: " << stu1->name << " years_old: " << stu1->value << endl;
    cout << "name: " << stu_ptr1->name << " years_old: " << stu_ptr1->value << endl;

      
#endif

    return 0;
}
    
#if 0

/*
 * 为了探究为什么需要设计智能指针，为了解决内存泄露等问题，设计为资源获取即初始化，使用构造函数进行资源的初始化，使用析构函数进行资源的释放。
 * 在c++98中设计了auto_ptr智能指针，在c++11弃用，c++17彻底删除
*/
#include <iostream>

using namespace std;

class Object{
    public:
        Object()
        {
            cout << "Create Object!" << endl;
        }
        ~Object()
        {
            cout << "Free Object!" << endl;
        }
        void run()
        {
            cout << "The test is to test smart pointer!" << endl;
        }
        void throw_test()
        {
            throw -1;
        }
};

int main(){

    /*
     * throw_test() 被调用后，抛出异常，此时下面的不能被执行，因此delete没有生效，会造成内存泄露，如果对于类似的忘记进行delete也会造成内存的泄露
     * 对此，C++C++之父Bjarne Stroustrup提出了 RAII(Resource Acquisition Is Initialization) 机制，
     *   翻译过来就是“资源获取就是初始化”。
     *   RAII要求由对象的构造函数完成资源的分配，同时由析构函数，完成资源的释放。在这种要求下，只要对象能正确地析构，就不会出现资源泄露问题。而 C++智能指针 正是RAII的实践。
     *   构造函数与析构函数的名字需要与类名一致
    */

    try{
        {
            Object* pObj = new Object();
            // pObj->run();
            pObj->throw_test();
            cout << "test1" << endl;
            delete pObj;
            cout << "test2" << endl;
        }
    }catch(...){
        cout << " 捕捉到异常！" << endl;

    }
    return 0;
}

#endif
